<?php
declare(strict_types=1);


namespace Reven\Web3;


use InvalidArgumentException;
use phpseclib\Math\BigInteger;
use phpseclib\Math\BigInteger as BigNumber;
use Reven\Result\Re;
use RuntimeException;
use Web3\Utils;

class Help
{
    public static function callBack($err,$res):Re{
        if ($err!=null){
            if ($err instanceof RuntimeException)
            {
                return self::reFail($err->getMessage())->setCode('500');
            }elseif(is_string($err) ){
                return self::reFail($err)->setCode('500');
            }
            return self::reFail('fail')->setCode('500');
        }
        return self::re($res);
    }

    public static function re($data=[],$str='success'):Re{
        return new Re(true,$str,$data);
    }

    public static function reFail($str='network busy',$data=[]):Re{
        return new Re(false,$str,$data);
    }


    public static function BigIntegerToStr($data){
        if ($data instanceof BigInteger){
            return $data->toString();
        }
        return $data;
    }


    /**
     * hexToBn
     * decoding hex number into decimal
     *
     * @param string $value
     * @return BigNumber
     */
    public static function hexToBn($value)
    {
        $value = Utils::stripZero($value);
        return (new BigNumber($value, 16));
    }

    /**
     * fromWeiToDecimalsString
     * Change number from wei to number of decimals.
     * For example:
     * $stringNumber = Utils::fromWeiToDecimalsString('1000000', 8); //0.01
     *
     * @param BigNumber|string|int $number
     * @param int $numberOfDecimals
     * @return string
     */
    public static function fromWeiToDecimalsString($number, int $numberOfDecimals) : string
    {
        $bn = self::toBn($number);

        $exponent = str_pad('1', $numberOfDecimals + 1, '0', STR_PAD_RIGHT);

        $bnt = new BigNumber($exponent);

        $conversion = $bn->divide($bnt);

        return self::transformDivisionToString($conversion, Utils::UNITS['wei'], $exponent);
    }


    /**
     * transformDivisionToString
     * Internal private fucntion to convert a [quotient, remainder] BigNumber division result,
     * to a human readable unit.decimals (12.3920012000)
     * The unit string is 1000...000 having # decimal zero positions
     *
     * @param $divisionArray
     * @param string $unitZerosOrigin string representing the origin unit's number of zeros
     * @param $unitZerosDestiny
     * @return string
     */
    private static function transformDivisionToString($divisionArray, $unitZerosOrigin, $unitZerosDestiny) : string
    {
        $left = $divisionArray[0]->toString();
        $right = $divisionArray[1]->toString();

        if ($right != "0")
        {
            $bnt_wei = new BigNumber($unitZerosOrigin);
            $bnt_unit = new BigNumber($unitZerosDestiny);

            $right_lead_zeros = strlen($bnt_unit->toString()) - strlen($bnt_wei->toString()) - strlen($right);

            for ($i = 0; $i < $right_lead_zeros; $i++) $right = '0' . $right;
            $right = rtrim($right, "0");

            return $left . '.' . $right;
        }
        else
        {
            return $left;
        }
    }

    /**
     * toBn
     * Change number or number string to bignumber.
     *
     * @param BigNumber|string|int $number
     * @return array|BigNumber
     */
    public static function toBn($number)
    {
        if ($number instanceof BigNumber){
            $bn = $number;
        }
        elseif (is_int($number)) {
            $bn = new BigNumber($number);
        }
        elseif (is_numeric($number)) {
            $number = (string) $number;

            if (Utils::isNegative($number)) {
                $count = 1;
                $number = str_replace('-', '', $number, $count);
                $negative1 = new BigNumber(-1);
            }
            if (strpos($number, '.') > 0) {
                $comps = explode('.', $number);

                if (count($comps) > 2) {
                    throw new InvalidArgumentException('toBn number must be a valid number.');
                }
                $whole = $comps[0];
                $fraction = $comps[1];

                return [
                    new BigNumber($whole),
                    new BigNumber($fraction),
                    strlen($comps[1]),
                    isset($negative1) ? $negative1 : false
                ];
            } else {
                $bn = new BigNumber($number);
            }
            if (isset($negative1)) {
                $bn = $bn->multiply($negative1);
            }
        }
        elseif (is_string($number)) {
            $number = mb_strtolower($number);

            if (Utils::isNegative($number)) {
                $count = 1;
                $number = str_replace('-', '', $number, $count);
                $negative1 = new BigNumber(-1);
            }
            if (Utils::isZeroPrefixed($number) || preg_match('/^[0-9a-f]+$/i', $number) === 1) {
                $number = Utils::stripZero($number);
                $bn = new BigNumber($number, 16);
            } elseif (empty($number)) {
                $bn = new BigNumber(0);
            } else {
                throw new InvalidArgumentException('toBn number must be valid hex string.');
            }
            if (isset($negative1)) {
                $bn = $bn->multiply($negative1);
            }
        }
        else {
            throw new InvalidArgumentException('toBn number must be BigNumber, string or int.');
        }
        return $bn;
    }

    /**
     * 将16进制转为number
     * @param $data
     * @param int $numberOfDecimals
     * @return string
     */
    public static function weiToNumber($data, int $numberOfDecimals)
    {
        // 初始化交易数量
        $strippedHexString = Utils::stripZero($data);
        // 转换为 BigNumber 对象
        $bigNumber = self::hexToBn($strippedHexString);

        return self::fromWeiToDecimalsString($bigNumber, $numberOfDecimals);
    }
}